import sys
from PyQt5.QtCore import pyqtSlot, QDir, pyqtSignal, QVariant, Qt
from PyQt5.QtWidgets import QWidget, QApplication, QMessageBox, QFileDialog
from PyQt5.QtGui import QImage, QPixmap
from setting_ui import Ui_Form
from configobj import ConfigObj
from hsv_search import HSVSearch
from binary_camera_thread import BinaryCameraThread
import platform


class SettingGUI(QWidget):
    # 发送给线程的关闭摄像头信号
    send_camera_close = pyqtSignal()
    # 发送 hsv值给线程[find_roadblock]
    send_hsv_changed = pyqtSignal(QVariant)
    # 发送是否反转图像黑白给线程[image_init]
    send_bitwise_not = pyqtSignal(bool)
    # 发送阈值[image_init]
    send_threshold_changed = pyqtSignal(int)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.conf = ConfigObj('./setting.ini', encoding='UTF8')
        self.hsv_object = None
        self.binary_object = None
        self.ui = Ui_Form()
        self.ui.setupUi(self)
        self.ui.lw_items.itemClicked.connect(self.lw_items_click)
        self.ui.btnQuit.clicked.connect(self.close)
        self.ui.gb_arduino.clicked.connect(self.gb_clicked)
        self.ui.gb_PCA9685.clicked.connect(self.gb_clicked)
        self.ui.hs_hmin.valueChanged.connect(self.slider_valueChanged)
        self.ui.hs_hhigh.valueChanged.connect(self.slider_valueChanged)
        self.ui.hs_smin.valueChanged.connect(self.slider_valueChanged)
        self.ui.hs_shigh.valueChanged.connect(self.slider_valueChanged)
        self.ui.hs_vmin.valueChanged.connect(self.slider_valueChanged)
        self.ui.hs_vhigh.valueChanged.connect(self.slider_valueChanged)
        self.ui.hs_binary_threshold.valueChanged.connect(self.hs_binary_valueChanged)

        self.load_setting()

    def hs_binary_valueChanged(self):
        value = self.ui.hs_binary_threshold.value()
        self.ui.le_image_init_threshold.setText(str(value))
        self.send_threshold_changed.emit(value)

    @pyqtSlot()
    def on_cb_bitwise_not_clicked(self):
        self.send_bitwise_not.emit(self.ui.cb_bitwise_not.isChecked())

    @pyqtSlot()
    def on_btn_binary_open_camera_clicked(self):
        if self.ui.btn_binary_open_camera.text() == "打开摄像头调试":
            self.ui.btn_binary_open_camera.setText("关闭摄像头")
            self.binary_object = BinaryCameraThread(camera=self.get_platform())
            self.binary_object.changePixmap.connect(self.set_binary_image)
            self.send_camera_close.connect(self.binary_object.do_stop)
            self.send_bitwise_not.connect(self.binary_object.update_bitwise_not)
            self.send_threshold_changed.connect(self.binary_object.update_binary)
            self.binary_object.start()
            self.hs_binary_valueChanged()
            self.on_cb_bitwise_not_clicked()
        else:
            if self.binary_object:
                self.send_camera_close.emit()
                self.binary_object = None
            self.ui.btn_binary_open_camera.setText("打开摄像头调试")

    @pyqtSlot()
    def on_btn_open_camera_clicked(self):
        if self.ui.btn_open_camera.text() == "打开摄像头调试":
            self.ui.btn_open_camera.setText("关闭摄像头")
            print("platform:{}".format(self.get_platform()))
            self.hsv_object = HSVSearch(camera=self.get_platform())
            self.send_camera_close.connect(self.hsv_object.do_stop)
            self.send_hsv_changed.connect(self.hsv_object.update_hsv)
            self.hsv_object.changePixmap.connect(self.set_image)
            self.hsv_object.start()
            self.slider_valueChanged()
        else:
            self.ui.btn_open_camera.setText("打开摄像头调试")
            if self.hsv_object:
                self.send_camera_close.emit()
                self.hsv_object = None

    def get_platform(self):
        """
        根据平台发货摄像头参数前缀
        """
        if platform.system().lower() == 'windows':
            return int(self.conf['camera']['line_camera'])
        elif platform.system().lower() == 'linux':
            return '/dev/video' + self.conf['camera']['line_camera']
        else:
            return None

    @pyqtSlot()
    def gb_clicked(self):
        if self.sender() == self.ui.gb_arduino:
            if self.ui.gb_arduino.isChecked():
                self.ui.gb_PCA9685.setChecked(False)
            else:
                self.ui.gb_PCA9685.setChecked(True)
        else:
            if self.ui.gb_PCA9685.isChecked():
                self.ui.gb_arduino.setChecked(False)
            else:
                self.ui.gb_arduino.setChecked(True)

    @pyqtSlot()
    def on_btn_model_dir_clicked(self):
        cur_path = QDir.currentPath()
        filt = "onnx文件(*.onnx)"
        filename, filtUsed = QFileDialog.getOpenFileName(self, "请选择自定义模型文件", cur_path, filt)
        if filtUsed:
            self.ui.le_rt_model.setText(filename + '')

    @pyqtSlot()
    def on_btnCancel_clicked(self):
        self.load_setting()

    @pyqtSlot()
    def on_btn_label_dir_clicked(self):
        cur_path = QDir.currentPath()
        filt = "txt文件(*.txt)"
        filename, filtUsed = QFileDialog.getOpenFileName(self, "请选择自定义标签文件", cur_path, filt)
        if filtUsed:
            self.ui.le_rt_label.setText(filename + '')

    def lw_items_click(self, item):
        self.ui.sw_main.setCurrentIndex(int(item.toolTip()))

    @pyqtSlot()
    def on_btnOk_clicked(self):
        self.save_setting()
        dlgtitle = "消息框"
        strInfo = "系统设置参数保存成功!，是否关闭窗口？"
        defaultBtn = QMessageBox.No
        result = QMessageBox.question(self, dlgtitle, strInfo, QMessageBox.Yes | QMessageBox.No, defaultBtn)
        if result == QMessageBox.Yes:
            self.close()
        else:
            self.conf.reload()


    @pyqtSlot(QImage)
    def set_image(self, image):
        image = image.scaled(240, 180, Qt.KeepAspectRatio)
        self.ui.lb_camera.setPixmap(QPixmap.fromImage(image))

    @pyqtSlot(QImage)
    def set_binary_image(self, image):
        image = image.scaled(240, 180, Qt.KeepAspectRatio)
        self.ui.lb_binary_image.setPixmap(QPixmap.fromImage(image))

    def slider_valueChanged(self):
        self.set_hsv_value()
        if self.hsv_object:
            hsv_list = []
            hsv_list.append(self.ui.hs_hmin.value())
            hsv_list.append(self.ui.hs_hhigh.value())
            hsv_list.append(self.ui.hs_smin.value())
            hsv_list.append(self.ui.hs_shigh.value())
            hsv_list.append(self.ui.hs_vmin.value())
            hsv_list.append(self.ui.hs_vhigh.value())
            self.send_hsv_changed.emit(QVariant(hsv_list))

    def set_hsv_value(self):
        value = 'h:' + str(self.ui.hs_hmin.value()) + '-' + str(self.ui.hs_hhigh.value()) + '; '
        value = value + 's:' + str(self.ui.hs_smin.value()) + '-' + str(self.ui.hs_shigh.value()) + '; '
        value = value + 'v:' + str(self.ui.hs_vmin.value()) + '-' + str(self.ui.hs_vhigh.value())
        self.ui.gb_hsv.setTitle('hsv：' + value)

    def load_setting(self):
        """
        读取配置文件中的配置参数，初始化控件的值或状态
        """
        # camera
        self.ui.cb_line_camera.setCurrentIndex(int(self.conf['camera']['line_camera']))
        self.ui.cb_od_camera.setCurrentIndex(int(self.conf['camera']['od_camera']))

        # car_controller
        if int(self.conf['car_controller']['type']) == 0:
            self.ui.gb_arduino.setChecked(True)
            self.ui.gb_PCA9685.setChecked(False)
        else:
            self.ui.gb_arduino.setChecked(False)
            self.ui.gb_PCA9685.setChecked(True)
        self.ui.cb_com.setCurrentIndex(int(self.conf['car_controller']['port']))

        for i in range(self.ui.cb_rate.count()):
            if self.ui.cb_com.itemText(i) == self.conf['car_controller']['rate']:
                self.ui.cb_com.setCurrentIndex(i)
                break
        if self.conf['car_controller']['receive_arduino'] == "True":
            self.ui.cb_receive_arduino.setChecked(True)
        else:
            self.ui.cb_receive_arduino.setChecked(False)

        self.ui.le_iic_address.setText(self.conf['car_controller']['iic_address'])
        self.ui.le_pwm.setText(self.conf['car_controller']['frequency'])
        if self.conf['car_controller']['receive_pca'] == "True":
            self.ui.cb_receive_pca.setChecked(True)
        else:
            self.ui.cb_receive_pca.setChecked(False)
        self.ui.cb_board_type.setCurrentIndex(int(self.conf['car_controller']['board_type']))
        self.ui.le_speed.setText(self.conf['car_controller']['base_speed'])
        self.ui.le_proportional.setText(self.conf['car_controller']['proportional'])

        # image_init
        cf = self.conf['image_init']
        self.ui.le_image_init_threshold.setText(cf['threshold'])
        self.ui.hs_binary_threshold.setValue(int(cf['threshold']))
        if cf['bitwise_not'] == "True":
            self.ui.cb_bitwise_not.setChecked(True)
        else:
            self.ui.cb_bitwise_not.setChecked(False)
        self.ui.cb_kernel_type.setCurrentIndex(int(cf['kernel_type']))
        self.ui.cb_iterations.setCurrentIndex(int(cf['iterations']))

        # follow_line
        cf = self.conf['follow_line']
        self.ui.le_follow_line_threshold.setText(cf['threshold'])
        self.ui.cb_direction.setCurrentIndex(int(cf['direction']))

        # find_intersection
        cf = self.conf['find_intersection']
        self.ui.le_radius.setText(cf['radius'])
        self.ui.le_dot_threshold.setText(cf['threshold'])
        self.ui.le_find_intersection_delay_time.setText(cf['delay_time'])
        self.ui.le_repeated_threshold.setText(cf['repeat_count'])

        # find_roadblock
        cf = self.conf['find_roadblock']
        self.ui.hs_hmin.setValue(int(cf['h_low']))
        self.ui.hs_hhigh.setValue(int(cf['h_high']))
        self.ui.hs_vmin.setValue(int(cf['v_low']))
        self.ui.hs_vhigh.setValue(int(cf['v_high']))
        self.ui.hs_smin.setValue(int(cf['s_low']))
        self.ui.hs_shigh.setValue(int(cf['s_high']))
        self.ui.le_findroadblock_threshold.setText(cf['threshold'])
        self.set_hsv_value()

        # find_zebra_crossing
        cf = self.conf['find_zebra_crossing']
        self.ui.le_zebra_threshold.setText(cf['threshold'])
        self.ui.le_floor_line_count.setText(cf['floor_line_count'])
        self.ui.le_zebra_delay_time.setText(cf['delay_time'])

        # object_detection
        cf = self.conf['object_detection']
        self.ui.cb_resolution.setCurrentIndex(int(cf['resolution']))
        self.ui.le_od_threshold.setText(cf['threshold'])
        self.ui.le_rt_model.setText(cf['rt_model'])
        self.ui.le_rt_label.setText(cf['rt_label'])
        if cf['custom_model'] == "True":
            self.ui.gb_custom_model.setChecked(True)
        else:
            self.ui.gb_custom_model.setChecked(False)

    def save_setting(self):
        """
        读取控件的值或状态，写入配置文件
        """
        # camera
        self.conf['camera']['line_camera'] = self.ui.cb_line_camera.currentIndex()
        self.conf['camera']['od_camera'] = self.ui.cb_od_camera.currentIndex()

        # car_controller
        if self.ui.gb_arduino.isChecked():
            self.conf['car_controller']['type'] = 0
        else:
            self.conf['car_controller']['type'] = 1
        self.conf['car_controller']['port'] = self.ui.cb_com.currentIndex()
        self.conf['car_controller']['rate'] = self.ui.cb_rate.currentText()
        self.conf['car_controller']['receive_arduino'] = str(self.ui.cb_receive_arduino.isChecked())
        self.conf['car_controller']['receive_pca'] = str(self.ui.cb_receive_pca.isChecked())
        self.conf['car_controller']['iic_address'] = self.ui.le_iic_address.text()
        self.conf['car_controller']['frequency'] = self.ui.le_pwm.text()
        self.conf['car_controller']['board_type'] = self.ui.cb_board_type.currentIndex()
        self.conf['car_controller']['base_speed'] = int(self.ui.le_speed.text())
        self.conf['car_controller']['proportional'] = self.ui.le_proportional.text()

        # image_init
        self.conf['image_init']['threshold'] = self.ui.le_image_init_threshold.text()
        self.conf['image_init']['bitwise_not'] = str(self.ui.cb_bitwise_not.isChecked())
        self.conf['image_init']['kernel_type'] = self.ui.cb_kernel_type.currentIndex()
        self.conf['image_init']['iterations'] = self.ui.cb_iterations.currentIndex()

        # follow_line
        self.conf['follow_line']['threshold'] = int(self.ui.le_follow_line_threshold.text())
        self.conf['follow_line']['direction'] = self.ui.cb_direction.currentIndex()

        # find_intersection
        self.conf['find_intersection']['radius'] = int(self.ui.le_radius.text())
        self.conf['find_intersection']['threshold'] = int(self.ui.le_dot_threshold.text())
        self.conf['find_intersection']['delay_time'] = float(self.ui.le_find_intersection_delay_time.text())
        self.conf['find_intersection']['repeat_count'] = int(self.ui.le_repeated_threshold.text())

        # find_roadblock
        self.conf['find_roadblock']['h_low'] = self.ui.hs_hmin.value()
        self.conf['find_roadblock']['h_high'] = self.ui.hs_hhigh.value()
        self.conf['find_roadblock']['s_low'] = self.ui.hs_smin.value()
        self.conf['find_roadblock']['s_high'] = self.ui.hs_shigh.value()
        self.conf['find_roadblock']['v_low'] = self.ui.hs_vmin.value()
        self.conf['find_roadblock']['v_high'] = self.ui.hs_vhigh.value()
        self.conf['find_roadblock']['threshold'] = float(self.ui.le_findroadblock_threshold.text())

        # find_zebra_crossing
        self.conf['find_zebra_crossing']['threshold'] = int(self.ui.le_zebra_threshold.text())
        self.conf['find_zebra_crossing']['floor_line_count'] = int(self.ui.le_floor_line_count.text())
        self.conf['find_zebra_crossing']['delay_time'] = int(self.ui.le_zebra_delay_time.text())

        # object_detection
        self.conf['object_detection']['custom_model'] = str(self.ui.gb_custom_model.isChecked())
        self.conf['object_detection']['resolution'] = self.ui.cb_resolution.currentIndex()
        self.conf['object_detection']['threshold'] = float(self.ui.le_od_threshold.text())
        self.conf['object_detection']['rt_model'] = self.ui.le_rt_model.text()
        self.conf['object_detection']['rt_label'] = self.ui.le_rt_label.text()

        self.conf.write()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    gui = SettingGUI()
    gui.show()
    sys.exit(app.exec_())
